package com.daxt.common.config;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.daxt.base.common.util.JwtCode;
import com.daxt.base.common.util.JwtUtil;
import com.daxt.base.common.util.RedisUtil;
import com.daxt.base.common.util.TokenInfo;
import com.daxt.common.annotations.LoginAuth;
import com.daxt.common.result.Result;
import com.daxt.common.result.ResultCode;
import com.daxt.common.result.ResultUtil;
import com.daxt.common.util.HttpWsUtil;
import com.daxt.mapper.sys.OperationLogMapper;
import com.daxt.mapper.sys.UserMapper;
import com.daxt.model.dic.ClientType;
import com.daxt.model.dic.SystemConfigType;
import com.daxt.model.dto.FourAUserDto;
import com.daxt.model.service.base.result.UserInfo;
import com.daxt.model.service.base.vo.BaseUser;
import com.daxt.model.service.base.vo.OperationLog;
import com.daxt.utils.IpUtil;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jws;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.ss.formula.functions.T;
import org.jasig.cas.client.authentication.AttributePrincipal;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;

import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.lang.reflect.Method;
import java.time.LocalDateTime;
import java.util.Map;

import static com.daxt.model.dic.LoginPattern.SSO;


public class AuthFilter extends HandlerInterceptorAdapter {
    //private final static String DEFAULT_FILTER_PATH = "/socket/test";
    @Autowired
    private RedisUtil redisUtil;

    ////    @Autowired
//    private UserService userService;
//    @Autowired
    private UserMapper userMapper;


    //	@Value("${license}")
    private String license;

    //	AuthFilter(String license){
//		this.license = license;
//	}
    AuthFilter(UserMapper userMapper) {
        this.userMapper = userMapper;
    }

    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
//    	//许可证
//		String md5Mac = Md5Util.hash(BaseUtil.getMACAddress() + "jtlt");
//		if(!StringUtils.isNotEmpty(license) || !md5Mac.equals(license)){
//			returnJson(response,ResultUtil.data(ResultCode.RESULT_ERROR.getCode(), "授权失败", null));
//			return false;
//		}
        // 如果不是映射到方法直接通过
        if (!(handler instanceof HandlerMethod)) {
            return true;
        }


        HandlerMethod handlerMethod = (HandlerMethod) handler;
        Method method = handlerMethod.getMethod();
        // 判断接口是否需要登录
        LoginAuth loginAuth = method.getAnnotation(LoginAuth.class);

        boolean flag = false;
        // 有 @LoginRequired 注解，需要认证
        if (loginAuth != null) {
            Result loginResult = loginVerify(request);
            if (loginResult.getCode() == ResultCode.RESULT_SUCCESS.getCode()) {

//                // CAS登录用户信息
//                AttributePrincipal principal = (AttributePrincipal) request.getUserPrincipal();
//                Map<String,Object> attributes = principal.getAttributes();
//                for(Map.Entry<String, Object> entry :attributes.entrySet()) {
//                    String key = entry.getKey();
//                    Object val = entry.getValue();
//                    System.out.printf("%s:%s\r\n",key,val);
//                }


                //注入登录信息
                flag = true;
                request.setAttribute("loginUser", loginResult.getData());
            } else {
                returnJson(response, loginResult);
            }

        } else {
            flag = true;
        }

        return flag;


    }


//    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception{
////    	//许可证
////		String md5Mac = Md5Util.hash(BaseUtil.getMACAddress() + "jtlt");
////		if(!StringUtils.isNotEmpty(license) || !md5Mac.equals(license)){
////			returnJson(response,ResultUtil.data(ResultCode.RESULT_ERROR.getCode(), "授权失败", null));
////			return false;
////		}
//    	System.out.println(request.getRequestURI());
//    	if (checkURI(request.getRequestURI(), request.getMethod())) {
//			return true;
//		} else {
//			String token;
//			if(request.getRequestURI().contains("socket")) {
//				token = request.getHeader("Sec-WebSocket-Protocol");
//
//			}else {
//				token = request.getHeader("Authorization");
//			}
//			System.out.println(request.getRequestURI());
//			System.out.println("token:"+token);
//			if (StringUtils.isNotBlank(token)) {
//				Map<String, Object> checkJWT = JwtUtil.checkJWT(token);
//				if ((boolean) checkJWT.get("result")) {
//					// Jws<Claims> parseJWT
//					Map<String, Object> parseJWT1 = JwtUtil
//							.parseJWT(JwtUtil.generateKey(JwtUtil.JWT_ALG, JwtUtil.JWT_RULE), token);
//					if (!(boolean) parseJWT1.get("result")) {
//						String code = parseJWT1.get("code").toString();
//						ResultCode valueOf = ResultCode.valueOf(code);
//						returnJson(response,ResultUtil.data(valueOf.getCode(), valueOf.getMes(),null));
//						return false;
//					}
//
//					@SuppressWarnings("unchecked")
//					Jws<Claims> parseJWT = (Jws<Claims>) parseJWT1.get("code");
//					String userId = parseJWT.getBody().getId();
//					String subject = parseJWT.getBody().getSubject();
//					String key=TokenInfo.getKey(userId,subject);
//					boolean hasKey = redisUtil.hasKey(key);
//					if (hasKey) {
//						/*UserInfo userInfo = (UserInfo) redisUtil.get(key);
//						if(!userInfo.getToken().equals(token)) {
//							returnJson(response,ResultUtil.data(ResultCode.TOKEN_SIGNATURE.getCode(), ResultCode.TOKEN_SIGNATURE.getMes(), null));
//							return false;
//						}*/
//						return true;
//
//					} else {
//						returnJson(response,ResultUtil.data(ResultCode.TOKEN_EXPIREDJWT.getCode(), ResultCode.TOKEN_EXPIREDJWT.getMes(), null));
//						return false;
//					}
//
//				} else if(ResultCode.TOKEN_MALFORMEDJWT.equals(checkJWT.get("code").toString())){
//					/* TokenInfo tokenInfo = JwtUtil.parseExpriToken(token);
//					if (tokenInfo!=null) {
//						String key = TokenInfo.getKey(tokenInfo.getId(),tokenInfo.getFrom());
//						if(redisUtil.hasKey(key)) {
//							returnJson(response,ResultUtil.data(ResultCode.TOKEN_SIGNATURE.getCode(), ResultCode.TOKEN_SIGNATURE.getMes(), null));
//							return false;
//						}
//					}
//					return true;*/
//					returnJson(response,ResultUtil.data(ResultCode.TOKEN_MALFORMEDJWT.getCode(), ResultCode.TOKEN_MALFORMEDJWT.getMes(), null));
//					return false;
//				}else {
//					String code = checkJWT.get("code").toString();
//					ResultCode valueOf = ResultCode.valueOf(code);
//					returnJson(response,ResultUtil.data(valueOf.getCode(), valueOf.getMes(), null));
//					return false;
//				}
//			} else {
//				returnJson(response,ResultUtil.data(ResultCode.TOKEN_NULL.getCode(), ResultCode.TOKEN_NULL.getMes(), null));
//				return false;
//			}
//
//		}
//        //return true;
//    }
//
//	private static boolean checkURI(String requestURI, String requestMethod) {
//		List<String> list = new ArrayList<String>();
//		//list.add("/admin/refToken");
//		list.add("/swagger-ui.html");
//		list.add("/login");
//		list.add("/index");
//		list.add("/");
//		list.add("/web/imageCode");
//		list.add("/web/sendMobile");
//		list.add("/doc.html");
//		list.add("/web/pv");
//		list.add("/web/authFile");
//		list.add("/fileManager/print");
//
//
//		list.add("/admin/course/user/watchCourse/export");
//
//
//		//list.add("/socket/test/*");
//
//		//list.add("/swagger-ui.html");
//		//list.add("/v2/api-docs");
//		//list.add("/");
//		//list.add("/csrf");
//
//		if(requestURI.contains("/swagger-ui.html")) {
//			return true;
//		}else if(requestURI.contains("/v2/api-docs")){
//			return true;
//		}
//		if(requestURI.startsWith("/web/"))
//			return true;
//		if(requestURI.startsWith("/resouce/"))
//			return true;
//		for (String string : list) {
//			if (string.contains("*")) {
//				string = string.replaceAll("\\*", "\\\\w*");
//			} else if (requestURI.equals(string)) {
//				return true;
//			}
//			if (Pattern.matches(string, requestURI)) {
//				return true;
//			}
//		}
//		return true;
//	}

    /**
     * @description: 登录验证
     * @author: lig
     * @date: 2021/11/10
     */
    private Result loginVerify(HttpServletRequest request) {


        String token;
        if (request.getRequestURI().contains("socket")) {
            token = request.getHeader("Sec-WebSocket-Protocol");

        } else {
            token = request.getHeader("Authorization");
        }

        System.out.println(request.getRequestURI());
        System.out.println("token:" + token);

        String login_pattern = RedisUtil.getSysConfig(SystemConfigType.LOGIN_PATTERN);
        String loginPattern = login_pattern;

        if(loginPattern.equals(SSO.getKey())){
            return casLogin(request);
        }
        return baseLogin(token);

//        Cookie[] cookies = request.getCookies();
//        //单点登录
//        for (Cookie cook : cookies) {
//            if (cook.getName().equals("JSESSIONID")) {
//                System.err.println("单点登录");
//                return casLogin(request);
//            }
//        }
//        return baseLogin(token);


    }


    private void returnJson(ServletResponse response, Result<T> result) {
        PrintWriter writer = null;
        response.setCharacterEncoding("UTF-8");
        response.setContentType("text/html; charset=utf-8");
        try {
            writer = response.getWriter();
            writer.print(JSON.toJSONString(result));

        } catch (IOException e) {
            //log.error("response error",e);
        } finally {
            if (writer != null)
                writer.close();
        }
    }

    private void generateToken(UserInfo userInfo) {
        String userInfoKey = TokenInfo.getKey(userInfo.getId().toString(), userInfo.getFrom());
        String userToken = JwtUtil.buildJWT(userInfo.getFrom(), userInfo.getId().toString(), JwtUtil.JWT_DURATION);
        userInfo.setToken(userToken);
        redisUtil.set(userInfoKey, userInfo, JwtUtil.JWT_DURATION);
    }


    /**
     * @description: 单点登录
     * @author: lig
     * @date: 2022/1/6
     */
    private Result casLogin(HttpServletRequest request) {
        //cas
        AttributePrincipal principal = (AttributePrincipal) request.getUserPrincipal();
        if (null != principal) {
            Map<String, Object> attributes = principal.getAttributes();

//            for (Map.Entry<String, Object> entry : attributes.entrySet()) {
//                String key = entry.getKey();
//                Object val = entry.getValue();
//                System.out.printf("%s:%s\r\n", key, val);
//            }
            String username = principal.getName();
            System.out.println("单点登录用户名:" + username);
//            id和account
//            String userId = attributes.get("id").toString();
//            String account = attributes.get("account").toString();
            String subject = ClientType.SSO.getKey();

            QueryWrapper<BaseUser> queryWrapper = new QueryWrapper<>();
            queryWrapper.eq("username", username);
            BaseUser baseUser = null;
            try {
                baseUser = userMapper.selectOne(queryWrapper);
            } catch (Exception e) {
                return ResultUtil.error("用户信息异常：" + username);
            }
            if (null == baseUser) {
                FourAUserDto aUserDto = HttpWsUtil.syscUserDataByName(username);
                if (null == aUserDto) return ResultUtil.error("用户提取不存在：" + username);
                baseUser = new BaseUser();
                baseUser.setUsername(aUserDto.getLoginName());
                baseUser.setRealName(aUserDto.getPerName());
                baseUser.setDeptIds(Long.parseLong(aUserDto.getDeptId()));
                baseUser.setCreateTime(LocalDateTime.now());
                baseUser.setState("1");
                userMapper.insert(baseUser);

                //记录登录日志
                /*String ip= IpUtil.getIP(request);
                OperationLog entity = new OperationLog();
                entity.setOtype("1");
                entity.setOcontent("登录");
                entity.setOperationBy(username);
                entity.setIp(ip);
                entity.setOperationDept(userInfo.getDeptName());
                entity.setFondsId(userInfo.getFondsId());
                entity.setCreateTime(LocalDateTime.now());
                operationLogMapper.insert(entity);*/
//                    return ResultUtil.error("用户不存在：" + username);
            }


            String userId = baseUser.getId().toString();
            redisUtil = RedisUtil.getInitRedis();
            String key = TokenInfo.getKey(userId, subject);
//            boolean hasKey = redisUtil.hasKey(key);
            UserInfo userInfo = (UserInfo) redisUtil.get(key);
            if (null == userInfo) {

                userInfo = new UserInfo();
                userInfo.setId(baseUser.getId());
                userInfo.setFrom(subject);
                userInfo.setUsername(username);
                generateToken(userInfo);

            }
            //校验token
            Map<String, Object> checkJWT = JwtUtil.checkJWT(userInfo.getToken());
            if (!(boolean) checkJWT.get("result") && checkJWT.get("code").equals(JwtCode.TOKEN_EXPIREDJWT)) {
                //刷新token
                generateToken(userInfo);

            }

            return ResultUtil.success(userInfo);
        } else {
            return ResultUtil.error("单点登录失败");
        }
    }


    /**
     * @description: 基础登录
     * @author: lig
     * @date: 2022/1/6
     */
    private Result baseLogin(String token) {
        if (StringUtils.isNotBlank(token)) {
            Map<String, Object> checkJWT = JwtUtil.checkJWT(token);
            if ((boolean) checkJWT.get("result")) {
                // Jws<Claims> parseJWT
                Map<String, Object> parseJWT1 = JwtUtil
                        .parseJWT(JwtUtil.generateKey(JwtUtil.JWT_ALG, JwtUtil.JWT_RULE), token);
                if (!(boolean) parseJWT1.get("result")) {
                    String code = parseJWT1.get("code").toString();
                    ResultCode valueOf = ResultCode.valueOf(code);
                    return ResultUtil.error(valueOf.getCode(), valueOf.getMes());
                }

                Jws<Claims> parseJWT = (Jws<Claims>) parseJWT1.get("code");
                String userId = parseJWT.getBody().getId();
                String subject = parseJWT.getBody().getSubject();
                String key = TokenInfo.getKey(userId, subject);
                redisUtil = RedisUtil.getInitRedis();
                boolean hasKey = redisUtil.hasKey(key);
                if (hasKey) {
                    UserInfo userInfo = (UserInfo) redisUtil.get(key);
                    //取消唯一登录点。
//                    if (!userInfo.getToken().equals(token)) {
//                        return ResultUtil.error(ResultCode.TOKEN_SIGNATURE.getCode(), ResultCode.TOKEN_SIGNATURE.getMes());
//                    }
                    return ResultUtil.success(userInfo);

                } else {
                    //token 过期  自动续期
                    UserInfo userInfo = (UserInfo) redisUtil.get(key);
                    if (null == userInfo) {
                        userInfo = new UserInfo();
                        userInfo.setId(Long.parseLong(userId));
                        userInfo.setFrom(subject);
                    }
                    generateToken(userInfo);

                    return ResultUtil.success(userInfo);
//                    return ResultUtil.error(ResultCode.TOKEN_EXPIREDJWT.getCode(), ResultCode.TOKEN_EXPIREDJWT.getMes());
                }

            } else if (ResultCode.TOKEN_MALFORMEDJWT.equals(checkJWT.get("code").toString())) {

                return ResultUtil.error(ResultCode.TOKEN_MALFORMEDJWT.getCode(), ResultCode.TOKEN_MALFORMEDJWT.getMes());

            } else {
                String code = checkJWT.get("code").toString();
                ResultCode valueOf = ResultCode.valueOf(code);
                return ResultUtil.error(valueOf.getCode(), valueOf.getMes());
            }
        }
        return ResultUtil.error(ResultCode.TOKEN_NULL.getCode(), ResultCode.TOKEN_NULL.getMes());
    }


}
